package com.swensen.game.data;

import java.awt.image.BufferedImage;

import com.swensen.game.data.BoardData.LevelType;
import com.swensen.game.data.FillTile.Neighbor;


/**
 * The Class TileMap.
 */
/**
 * @author swensen
 *
 */
public class TileMap {
	
	/** The height. */
	private int height;
	
	/** The tiles. */
	private Tile[][][] tiles;
	
	/** The width. */
	private int width;
	
	/**
	 * Instantiates a new tile map.
	 *
	 * @param width the width
	 * @param height the height
	 */
	public TileMap(int width, int height) {
		this.width = width;
		this.height = height;
		clear();
	}
	
	/**
	 * Check bounds.
	 *
	 * @param level the level
	 * @param x the x
	 * @param y the y
	 */
	private void checkBounds(int level, int x, int y) {
		if (level < 0 || level >= LevelType.COUNT || x < 0 || x >= width || y < 0 || y >= height) {
			throw new ArrayIndexOutOfBoundsException("Invalid TileMap location");
		}
	}
	
	/**
	 * Gets the height.
	 *
	 * @return the height
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * Gets the image.
	 *
	 * @param level the level
	 * @param x the x
	 * @param y the y
	 * @return the image
	 */
	public BufferedImage getImage(int level, int x, int y) {
		Tile tile = getTile(level, x, y);
		TileSet set = GameState.getCurrentTileSet();
		return tile == null || set == null ? null : set.getImage(tile.getImageData());
	}
	
	public boolean isEmptyOrCurrentTile(Tile current, int level, int x, int y) {
		Tile tile = getTile(level, x, y);
		return tile == null || tile.equals(current);
	}
	
	/**
	 * Gets the tile.
	 *
	 * @param level the level
	 * @param x the x
	 * @param y the y
	 * @return the tile
	 */
	public Tile getTile(int level, int x, int y) {
		checkBounds(level, x, y);
		return tiles[level][x][y];
	}

	/**
	 * Gets the width.
	 *
	 * @return the width
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * Sets the tile.
	 *
	 * @param tile the tile
	 * @param level the level
	 * @param x the x
	 * @param y the y
	 */
	public void setTile(Tile tile, int level, int x, int y) {
		checkBounds(level, x, y);
		
		if ((tile == null && tiles[level][x][y] == null)
				|| (tile != null && tile.equals(tiles[level][x][y])))
		{
			return;
		}
		
		if (tiles[level][x][y] instanceof FillTile && !tiles[level][x][y].equals(tile)) {
			int rows = tiles[level].length;
			
			for (int i = Math.max(x - 1, 0); i < Math.min(rows, x + 1); ++i) {
				int cols = tiles[level][i].length;
				for (int j = Math.max(y - 1, 0); j < Math.min(cols, y + 1); ++j) {
					FillTile neighbor;
					if (tiles[level][i][j] instanceof FillTile &&
							tile.equals(neighbor = (FillTile)tiles[level][i][j])) {
						switch(i - x) {
						case -1:
							switch(j - y){
							case -1:
								neighbor.removeNeighbor(Neighbor.SOUTH_EAST);
								break;
							case 0:
								neighbor.removeNeighbor(Neighbor.EAST);
								break;
							case 1:
								neighbor.removeNeighbor(Neighbor.NORTH_EAST);
								break;
							}
							break;
						case 0:
							switch(j - y){
							case -1:
								neighbor.removeNeighbor(Neighbor.SOUTH);
								break;
							case 1:
								neighbor.removeNeighbor(Neighbor.NORTH);
								break;
							}
							break;
						case 1:
							switch(j - y){
							case -1:
								neighbor.removeNeighbor(Neighbor.SOUTH_WEST);
								break;
							case 0:
								neighbor.removeNeighbor(Neighbor.WEST);
								break;
							case 1:
								neighbor.removeNeighbor(Neighbor.NORTH_WEST);
								break;
							}
							break;
						}
					}
				}
			}
		}
		
		tiles[level][x][y] = tile;
		
		if (tile instanceof FillTile) {
			int rows = tiles[level].length;
			
			for (int i = Math.max(x - 1, 0); i < Math.min(rows, x + 1); ++i) {
				int cols = tiles[level][i].length;
				for (int j = Math.max(y - 1, 0); j < Math.min(cols, y + 1); ++j) {
					FillTile neighbor;
					if (tiles[level][i][j] instanceof FillTile &&
							tile.equals(neighbor = (FillTile)tiles[level][i][j])) {
						switch(i - x) {
						case -1:
							switch(j - y){
							case -1:
								((FillTile)tile).addNeighbor(Neighbor.NORTH_WEST);
								neighbor.addNeighbor(Neighbor.SOUTH_EAST);
								break;
							case 0:
								((FillTile)tile).addNeighbor(Neighbor.WEST);
								neighbor.addNeighbor(Neighbor.EAST);
								break;
							case 1:
								((FillTile)tile).addNeighbor(Neighbor.SOUTH_WEST);
								neighbor.addNeighbor(Neighbor.NORTH_EAST);
								break;
							}
							break;
						case 0:
							switch(j - y){
							case -1:
								((FillTile)tile).addNeighbor(Neighbor.NORTH);
								neighbor.addNeighbor(Neighbor.SOUTH);
								break;
							case 1:
								((FillTile)tile).addNeighbor(Neighbor.SOUTH);
								neighbor.addNeighbor(Neighbor.NORTH);
								break;
							}
							break;
						case 1:
							switch(j - y){
							case -1:
								((FillTile)tile).addNeighbor(Neighbor.NORTH_EAST);
								neighbor.addNeighbor(Neighbor.SOUTH_WEST);
								break;
							case 0:
								((FillTile)tile).addNeighbor(Neighbor.EAST);
								neighbor.addNeighbor(Neighbor.WEST);
								break;
							case 1:
								((FillTile)tile).addNeighbor(Neighbor.SOUTH_EAST);
								neighbor.addNeighbor(Neighbor.NORTH_WEST);
								break;
							}
							break;
						}
					}
				}
			}
		}
	}

	public void clear() {
		tiles = new Tile[LevelType.COUNT][width][height];
	}
	
	
}
